package com.base.service;

import com.base.CoreConstants;
import com.base.cache.CacheSupport;
import com.base.cos.MyCosClient;
import com.base.dao.BFileMapper;
import com.base.dao.model.BFile;
import com.base.dao.model.BFileExample;
import com.base.des.Md5;
import com.base.io.FileTypeUtil;
import com.base.oss.MyOssClient;
import com.base.support.FileExportUtils;
import com.base.support.LogKit;
import com.base.util.*;
import com.base.util.video.FFMpegUtil;
import com.base.util.video.VideoConRun;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.util.*;

@Service
public class BFileService {
	@Autowired
	private BFileMapper bFileMapper;

	public static final String LOCAL = "local";
	public static final String OSS = "oss";
	public static final String COS = "cos";

	private static final Logger logger = Logger.getLogger(BFileService.class);

	public int countByExample(BFileExample example) {
		return this.bFileMapper.countByExample(example);
	}

	public BFile selectByPrimaryKey(String fileId) {
		return this.bFileMapper.selectByPrimaryKey(fileId);
	}

	public List<BFile> selectByExample(BFileExample example) {
		return this.bFileMapper.selectByExample(example);
	}

	public int deleteByPrimaryKey(String fileId) {
		return this.bFileMapper.deleteByPrimaryKey(fileId);
	}

	public int updateByPrimaryKeySelective(BFile record) {
		return this.bFileMapper.updateByPrimaryKeySelective(record);
	}

	public int updateByPrimaryKey(BFile record) {
		return this.bFileMapper.updateByPrimaryKey(record);
	}

	public int deleteByExample(BFileExample example) {
		return this.bFileMapper.deleteByExample(example);
	}

	public int updateByExampleSelective(BFile record, BFileExample example) {
		return this.bFileMapper.updateByExampleSelective(record, example);
	}

	public int updateByExample(BFile record, BFileExample example) {
		return this.bFileMapper.updateByExample(record, example);
	}

	public int insert(BFile record) {
		return this.bFileMapper.insert(record);
	}

	public int insertSelective(BFile record) {
		return this.bFileMapper.insertSelective(record);
	}

	public String uploadHeadImg(String url) {
		try {
			String savePath = UUID.randomUUID().toString();
			byte[] bytes = URLUtil.download(url);

			String type = FileTypeUtil.getType(bytes);
			if (type != null)
				savePath += "." + type.toLowerCase();
			return uploadFile(bytes, savePath, null);
		} catch (Exception e) {
			return null;
		}
	}

	public String getVideoImg(String id, String cut) throws Exception {
		if (StringUtil.isBlank(id))
			return null;
		BFile item = bFileMapper.selectByPrimaryKey(id);
		if (item == null) {
			logger.error("文件不存在;id=" + id);
			return null;
		} else {
			if (StringUtil.isNotBlank(cut)) {
				if (!cut.equals(item.getFileCreater())) {
					item.setFileCreater(cut);
					bFileMapper.updateByPrimaryKey(item);
				}
				return cut;
			} else {
				// 生成
				String cutImg = UUID.randomUUID().toString().replace("-", "");
				Calendar cal = Calendar.getInstance();
				String realdir = cal.get(Calendar.YEAR) + "-"
						+ (cal.get(Calendar.MONTH) + 1) + "-"
						+ (cal.get(Calendar.DAY_OF_MONTH)) + "/"
						+ "png";
				File f = new File(CoreConstants.FILE_PATH, realdir);
				if (!f.isDirectory()) {
					f.mkdirs();
				}
				File filepath = new File(CoreConstants.FILE_PATH + "/"
						+ item.getFilePath());
				File uploadedImgFile = new File(f.getPath(), cutImg + ".png");
				if (filepath.exists() && uploadedImgFile.exists()) {
					BFile image = new BFile();
					image.setFileId(cutImg);
					image.setFileMinitype("image/png");
					image.setFilePath(realdir + "/" + cutImg + ".png");
					image.setFileState(1);
					image.setFileCreatetime(new Date());
					image.setFileName("videocut.png");
					image.setFileCreater("320x240");
					image.setFileBelong(BFileService.LOCAL);
					int i = bFileMapper.insert(image);
					if (i > 0) {
						item.setFileCreater(cutImg);
						bFileMapper.updateByPrimaryKey(item);
					}

				}
				return cutImg;
			}
		}
	}

	/**
	 * 获取文件
	 * 
	 * @param id
	 * @param w
	 * @param h
	 * @param q
	 * @param resp
	 * @param type
	 * @throws Exception
	 */
	public void getFile(String id, String w, String h, String q,
			HttpServletResponse resp, String type, HttpServletRequest request)
			throws Exception {
		if (id != null) {
			BFile item;
			if (id.startsWith("http://") || id.startsWith("https://")){
				resp.sendRedirect(id);
				return;
			}else if (id.indexOf("/") == 0){
				//第一个字符是/
				item = new BFile();
				item.setFilePath(id);
				item.setFileBelong(LOCAL);
				item.setFileName(id);
				item.setFileMd5(Md5.mD5(id));
				item.setFileMinitype(FileExportUtils.isImage(id)?"image":"video");
			}else{
				int dot = id.indexOf(".");
				if (dot != -1) {
					id = id.substring(0, dot);
				}
				item = bFileMapper.selectByPrimaryKey(id);
			}

			if (item == null) {
				if (id.endsWith(CoreConstants.VIDEO_NORMAL)){
					getFile(id.substring(0,id.indexOf(CoreConstants.VIDEO_NORMAL)),w,h,q,resp,type,request);
					return;
				}else if (id.endsWith(CoreConstants.VIDEO_264)){
					getFile(id.substring(0,id.indexOf(CoreConstants.VIDEO_264)),w,h,q,resp,type,request);
					return;
				}else{
					logger.error("文件不存在;id=" + id);
					return;
				}
			} else {
				int width = 0, height = 0, quality = 0;
				if (w != null && w.length() > 0) {
					width = Integer.valueOf(w);
				}
				if (h != null && h.length() > 0) {
					height = Integer.valueOf(h);
				}
				if (q != null && q.length() > 0) {
					quality = Integer.valueOf(q);
				}
				File filepath = new File(CoreConstants.FILE_PATH + "/"
						+ item.getFilePath());

				if (!LOCAL.equals(item.getFileBelong())) {
					String url = "https://"+item.getFileBelong()+ "/"
							+ URLEncoder.encode(item.getFilePath(), "utf-8");
					if (width + height != 0
							&& item.getFileMinitype().startsWith("image")) {
						if (height == 0) {
							url += "?x-oss-process=image/resize,w_" + width;
						} else if (height != 0 && width != 0) {
							url += "?x-oss-process=image/resize,w_" + width
									+ ",h_" + height;
						}
						resp.sendRedirect(url);
					} else {
						resp.sendRedirect(url);
					}
					return;
				}
				if (width + height != 0
						&& item.getFileMinitype().startsWith("image")) {
					// 检查目录
					File tempDirectory = new File(CoreConstants.FILE_PATH
							+ "/temp/");
					if (!tempDirectory.isDirectory()) {
						tempDirectory.mkdirs();
					}

					String tf = CoreConstants.FILE_PATH + "/temp/"
							+ item.getFileMd5() + "_" + width + "x" + height
							+ "x" + quality + ".jpg";
					File tempfile = new File(tf);
					if (tempfile.exists()) {
						filepath = tempfile;
					} else {
						ImageUtil.scale(filepath, tempfile, width, height, null);
						filepath = tempfile;
					}

				}

				if (item.getFileMinitype().startsWith("image")) {
					type = "inline";
				} else if (item.getFileMinitype().startsWith("video")) {
					String path = CoreConstants.VIDEO_PATH;
					if (IPUtil.isLocal(IPUtil.getClientIP(request))&& StringUtil.isNotBlank(CoreConstants.VIDEO_INNER_PATH)){
						path = CoreConstants.VIDEO_INNER_PATH;
					}
					resp.sendRedirect(path +item.getFilePath());
					return;
				}

				resp.setContentType(item.getFileMinitype() + "; charset=utf-8");
				if (!filepath.exists()) {
					logger.error("文件没找到;id=" + id);
					return;
				}
				FileExportUtils.download(request,resp, item.getFileName(),
						item.getFileMinitype(), filepath, type);
			}
		}
	}

	public boolean cutImage(File file,BufferedImage bufferedImage,String w, String h){
		int width = 0, height = 0;
		if (w != null && w.length() > 0) {
			width = Integer.valueOf(w);
		}
		if (h != null && h.length() > 0) {
			height = Integer.valueOf(h);
		}
		if (width != 0 && height != 0){
			double widthSize = width*1d/bufferedImage.getWidth();
			double heightSize = height*1d/bufferedImage.getHeight();
			if (widthSize == heightSize){
				return false;
			}
			if (widthSize > heightSize){
				width = bufferedImage.getWidth();
				height = (int) (bufferedImage.getHeight()*heightSize/widthSize);
			}else{
				width = (int) (bufferedImage.getWidth()*widthSize/heightSize);
				height = bufferedImage.getHeight();
			}
			ImageUtil.cut(file,file,0,0,width,height);
			return true;
		}
		return false;
	}

	/**
	 * 文件上传
	 * 
	 * @param bytes
	 *            文件
	 * @param fileName
	 *            文件名:xxx.jpg
	 * @param belong
	 *            归属
	 * @return
	 */
	public String uploadFile(byte[] bytes, String fileName, String belong) {
		// 文件保存目录路径
		String savePath = CoreConstants.FILE_PATH;
		String md5 = "";
		try {
			md5 = Md5.md5(bytes);
		} catch (Exception e1) {
			e1.printStackTrace();
		}
		BFileExample example = new BFileExample();
		example.createCriteria().andFileMd5EqualTo(md5);
		List<BFile> lf = this.selectByExample(example);
		if (lf.size() > 0) {
			return lf.get(0).getFileId();
		}
		long itemsize = bytes.length;
		// 检查文件大小
		if (itemsize > Long.parseLong(CoreConstants.FILE_MAXSIZE)) {
			return null;
		}
		// 检查扩展名
		String fileExt = fileName.substring(fileName.lastIndexOf(".") + 1)
				.toLowerCase();
		String newFileName = UUID.randomUUID().toString().replace("-", "");
		try {
			String minetype = FileExportUtils.getMine(bytes);
			Calendar cal = Calendar.getInstance();
			String realdir = minetype + "/" +cal.get(Calendar.YEAR)+"-"+(cal.get(Calendar.MONTH)+1)+"-"+(cal.get(Calendar.DAY_OF_MONTH));
			File f = new File(savePath, realdir);
			if (!f.isDirectory()) {
				f.mkdirs();
			}
			File uploadedFile = new File(f.getPath(), newFileName + "."
					+ fileExt);
			FileOutputStream fos = new FileOutputStream(uploadedFile);
			fos.write(bytes);
			fos.close();
			minetype = FileExportUtils.getMineType(uploadedFile.getPath());
			BFile ac = new BFile();
			ac.setFileId(newFileName);
			ac.setFileMinitype(minetype);
			ac.setFilePath(realdir + "/" + newFileName + "." + fileExt);
			ac.setFileState(1);
			ac.setFileSize(BigDecimal.valueOf(itemsize));
			ac.setFileMd5(md5);
			ac.setFileCreatetime(new Date());
			ac.setFileName(fileName);
			ac.setFileBelong(belong);

			if (FileExportUtils.isImage(fileName)) {
				BufferedImage bufferedImage = ImageIO.read(uploadedFile);
				int width = bufferedImage.getWidth();
				int height = bufferedImage.getHeight();
				ac.setFileCreater(width + "x" + height);
			}else if (FileExportUtils.isVideo(minetype)) {
				//上传截图
				String cutImgName = uploadVideo(uploadedFile,f.getPath(),realdir,newFileName,itemsize);
				ac.setFileCreater(cutImgName);
			}

			uploadFile(ac,uploadedFile,fileName);
		} catch (Exception e) {
			e.printStackTrace();
			logger.error(e);
			return null;
		}
		return newFileName;
	}

	/**
	 * 上传视频
	 */
	public String uploadVideo(File video,String path, String realdir, String newFileName,long itemsize) throws Exception{
		//上传截图
		if (StringUtil.isNotBlank(CoreConstants.FFMPEG_PATH)){
			FFMpegUtil ffMpegUtil = new FFMpegUtil(video);
			//视频截图
			String cutImgName = newFileName+ CoreConstants.VIDEO_CUR_IMG+".jpg";
			File cutImgFile = new File(path,cutImgName);
			ffMpegUtil.makeScreenCut(cutImgFile);
			BFile image = new BFile();
			image.setFileId(newFileName+ CoreConstants.VIDEO_CUR_IMG);
			image.setFileMinitype("image/jpeg");
			image.setFilePath(realdir + "/" + cutImgName);
			image.setFileState(1);
			image.setFileCreatetime(new Date());
			image.setFileName(cutImgName);
			image.setFileCreater(CoreConstants.VIDEO_SCREEN);
			uploadFile(image,cutImgFile,cutImgName);
			if ("true".equals(CoreConstants.VIDEO_TRANSFER)){
				VideoConRun run = new VideoConRun(ffMpegUtil,path,realdir,newFileName, this, CoreConstants.VIDEO_264,null);
				if ("true".equals(CoreConstants.VIDEO_TRANSFER_SYNC)){
					run.run();
				}else {
					ThreadUtil.execute(run);
				}
			}
			int time = ffMpegUtil.getRuntime();
			if ("true".equals(CoreConstants.VIDEO_ZIP)){
				if (itemsize / time > 100000){
					//视频
					ThreadUtil.execute(new VideoConRun(ffMpegUtil,path,realdir,newFileName, this, CoreConstants.VIDEO_NORMAL, CoreConstants.VIDEO_SCREEN));
				}
			}

			return image.getFileId();
		}
		return null;
	}

	/**
	 * 获取图片长宽
	 * 
	 * @param fileId
	 * @return
	 */
	public String getSize(String fileId) {
		String size = CacheSupport.get("imageSizeCache",
				"BFileService.getSize." + fileId, String.class);
		if (StringUtil.isBlank(size)) {
			BFile file = this.bFileMapper.selectByPrimaryKey(fileId);
			if (file != null && StringUtil.isNotBlank(file.getFileCreater())) {
				CacheSupport.put("imageSizeCache", "BFileService.getSize."
						+ fileId, file.getFileCreater());
				return file.getFileCreater();
			}
			return "";
		}
		return size;
	}

	/**
	 * 格式化图片ids:id|w|h,id|w|h
	 * 
	 * @param ids
	 * @return
	 */
	public String format(String ids) {
		if (StringUtil.isBlank(ids))
			return "";
		String[] idArray = ids.split(",");
		String size = "";
		List<String> strs = new ArrayList<String>();
		for (String id : idArray) {
			size = getSize(id);
			if (StringUtil.isNotBlank(size)) {
				id = id + "|" + size.replace("x", "|");
			} else {
				id = id + "||";
			}
			strs.add(id);
		}
		return StringUtil.listToString(strs);
	}

	public static String getTomcatWebappsPath(HttpServletRequest request){
		String tomcatRoot = request.getSession().getServletContext().getRealPath("/");
		String[] foo = tomcatRoot.split("/");
		StringBuilder tomcatWebAppsBuilder = new StringBuilder();
		int i = 0;
		for(String paths : foo){
			++i;
			if(i != foo.length){
				tomcatWebAppsBuilder.append(paths);
				tomcatWebAppsBuilder.append("/");
			}
		}
		String tomcatWebApps = tomcatWebAppsBuilder.toString();
		return tomcatWebApps;
	}

	public String uploadFile(BFile bFile, File source, String fileName) throws Exception{
		if(BFileService.OSS.equals(CoreConstants.FILE_MODE)){
			boolean b = MyOssClient.putObject(bFile.getFilePath(), bFile.getFileMinitype(), new FileInputStream(source), null, fileName);
			if(b){
				bFile.setFileBelong(MyOssClient.getHead());
				if (source.exists()){
					source.delete();
				}
			}else{
				LogKit.error("上传压缩视频文件失败,fileName:{}",fileName);
				return null;
			}
		}else if(BFileService.COS.equals(CoreConstants.FILE_MODE)){
			boolean b = MyCosClient.uploadFile(source,"/"+bFile.getFilePath(),bFile.getFileMinitype(),fileName);
			if (b){
				bFile.setFileBelong(MyCosClient.getBelong());
				if (source.exists()) {
					source.delete();
				}
			}
		} else{
			bFile.setFileBelong(BFileService.LOCAL);

		}
		this.insert(bFile);
		return bFile.getFileId();
	}
}